/* //device/system/broncho-ril/reference-ril.c
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include <telephony/ril.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <alloca.h>
#include "atchannel.h"
#include "at_tok.h"
#include "ril_util.h"
#include <getopt.h>
#include "broncho-ril.h"

#define LOG_TAG "RIL"
#include "broncho_log.h"

#define PLMN_NAME_FORMAT_NR	3

#define PLMN_NAME_FORMAT_NR	3
static const struct timeval TIMEVAL_NETPOLL = {5,0};
static void initSyscfg(RIL* thiz);
/*broncho yinlijun add begin */
static const struct timeval TIMEVAL_REGPOLL = {10,0};
static const struct timeval TIMEVAL_SYSCFGPATCH  = {30,0};
/*broncho yinlijun dd end*/

typedef struct _MmContext
{
	int	usb_power;
	int reg_success;
}MmContext;

static MmContext* getMmContext(RIL* thiz)
{
	MmContext* ctx = RIL_GetPrivInfo(thiz, "mm_ctx");
	
	if(ctx == NULL)
	{
		ctx = calloc(1, sizeof(MmContext));
		RIL_SetPrivInfo(thiz, ctx, "mm_ctx");
	}

	return ctx;

}

static void mmSetUsbPower(RIL* thiz, int on)
{
	MmContext* ctx = getMmContext(thiz);
	
	if(ctx->usb_power != on) 
	{
		ctx->usb_power = on;
		RIL_PowerUsbDevice(thiz, on);
	}

	return;
}

static void mmSetRegSuccess(RIL* thiz, int success)
{
	MmContext* ctx = getMmContext(thiz);
	ctx->reg_success = success;

	return;
}

int RIL_GetRegistState(RIL* thiz)
{
	MmContext* ctx = getMmContext(thiz);
	
	return ctx->reg_success;
}

static void requestSetPreferredNetworkType(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	int type = ((int*)data)[0];
	/* type = 1, use 2G only
	 * type = 0, !use 2G only
	 * */
	/*
	if(type == 0)
	{
		//ril_command_exec_for_result(thiz, "AT^SYSCFG=13,0,40000000,255,2");
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else if(type == 1)
	{
		//ril_command_exec_for_result(thiz, "AT^SYSCFG=2,0,40000000,255,2");
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}*/
	RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);

	return;
}

static void requestGetPreferredNetworkType(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	int type = 1;
	int ignored = 0;
	int result = 0;
	ATResponse* p_response = NULL;
	/*
	if(ril_command_exec_singleline_for_result(thiz, "AT^SYSCFG?", "^SYSCFG:", &p_response))
	{
		result = at_line_scanf_int_int_int_int_int(p_response->p_intermediates->line, &type, &ignored, &ignored, &ignored, &ignored);
	}
	if(result)
	{
		if(type == 13) //GSM ONLY
		{
			type = 1;
		}
		else
		{
			type = 0;
		}
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &type, sizeof(type));
	}*/

	//RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &type, sizeof(type));

	RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);

	return;
}

static void requestSetLocationUpdates(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	int enable = ((int*)data)[0];
	char* cmd = NULL;

	if (enable == 0)
	{
		cmd = "AT+CREG=0";
	}
	else
	{
		cmd = "AT+CREG=2";
	}

	if(ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}
/*broncho wupeng add begin.*/
static void requestCallGpsone(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	if(ril_command_exec_for_result(thiz, "AT^GPSONE"))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	return;
}

static void requestSetGps(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	int enable = 0;
	char cmd[32];
	
	enable = ((int*)data)[0];

	if(enable)
	{
		snprintf(cmd, 32, "AT^GPSSTART");
	}
	else
	{
		snprintf(cmd, 32, "AT^GPSSTOP");
	}

	if(ril_command_exec_for_result(thiz, cmd))
	{
		if(enable) 
		{
			property_set("system.gps.device", RIL_GetGpsChannelDeviceName(thiz));
			mmSetUsbPower(thiz, 1);
		} 
		else 
		{
			mmSetUsbPower(thiz, 0);
		}
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestQueryScreenState(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	int state = 0;
	char cmd[32] = {0};
	int cmd_ret = 0;

	state = ((int*)data)[0];
	if(state == 1)
	{
		ril_send_command(thiz, "AT^CURC=1", NULL);
		cmd_ret = ril_command_exec_for_result(thiz, "AT+CREG=2");
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);
	}
	else
	{
		ril_send_command(thiz, "AT^CURC=0", NULL);
		cmd_ret = ril_command_exec_for_result(thiz, "AT+CREG=0");
	}
	
	if(cmd_ret == 0)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}

	return;
}

static void requestQueryAvailableNetworks(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	int err = 0;
	int availableOptNumber = 0;
	int brackets = 0;
	int ignored = 0;

	char* line = NULL;
	char* p = NULL;
	char** result = NULL;
	ATResponse* p_resp = NULL;
	int i = 0;

	do
	{
		err = ril_send_command_multiline_full(thiz, "AT+COPS=?", 100000, "+COPS:", &p_resp);
		if (err != 0 || p_resp->success == 0) break;

		line = p_resp->p_intermediates->line;
		err = at_tok_start(&line);
		if (err < 0) break;

		for (p = line ; *p != '\0' ;p++)
		{
			if (*p == '(') brackets++;
		}
		//as the details, please refer to AT doc.
		availableOptNumber = brackets - 2;

		result = alloca(availableOptNumber*4*sizeof(char*));
		while(i < availableOptNumber)
		{
			int status = 0;
			at_tok_nextint(&line, &status);
			switch(status){
				case 1:
					result[i*4+3] = "available";
					break;
				case 2:
					result[i*4+3] = "current";
					break;
				case 3:
					result[i*4+3] = "forbidden";
					break;
				default:
					result[i*4+3] = "unknown";
					break;
			}

			at_tok_nextstr(&line, &result[i*4]);
			at_tok_nextstr(&line, &result[i*4+1]);
			at_tok_nextstr(&line, &result[i*4+2]);
			at_tok_nextint(&line, &ignored);
			i++;
		}
	}while(0);

	if (err < 0)
	{
		ALOGE("requestQueryAvailableNetworks must never return error when radio is on");
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, result, sizeof(char*)*availableOptNumber*4);
	}
	at_response_free(p_resp);

	return;
}

static void requestSetNetworkSelectionManual(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	char cmd[32] = {0};
	const char* oper = NULL;

	oper = (const char*)data;
	snprintf(cmd, 32, "AT+COPS=1,2,\"%s\"", oper);
	if (ril_command_exec_full_for_result(thiz, cmd, 60000))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		//think will bug, if fail to set manual, reset to auto mode.
		ril_command_exec_full_for_result(thiz, "AT+COPS=0", 60000);
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestSetNetworkSelectionAutomatic(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	int err = 0;
    ATResponse *p_response = NULL;
    int seletionMode = 0;
    char *line = NULL;

	do
	{
    	err = ril_send_command_singleline_full(thiz, "AT+COPS?", 60000, "+COPS:", &p_response);
    	if (err < 0 || p_response->success == 0) {
			break;
    	}

    	line = p_response->p_intermediates->line;
    	err = at_tok_start(&line);
    	if (err < 0) {
			break;
    	}

    	err = at_tok_nextint(&line, &seletionMode);
    	if (err < 0) {
			break;
    	}
	}while(0);

	if(err >= 0 && seletionMode == 0)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else if(ril_command_exec_full_for_result(thiz, "AT+COPS=0", 60000))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);

	return;
}

static void requestQueryNetworkSelectionMode(RIL* thiz, 
                void *data, size_t datalen, RIL_Token t)
{
    int err = 0;
    ATResponse *p_response = NULL;
    int response = 0;
    char *line = NULL;

	do
	{
    	err = ril_send_command_singleline_full(thiz, "AT+COPS?", 60000, "+COPS:", &p_response);
    	if (err < 0 || p_response->success == 0) {
			break;
    	}

    	line = p_response->p_intermediates->line;
    	err = at_tok_start(&line);
    	if (err < 0) {
			break;
    	}

    	err = at_tok_nextint(&line, &response);
    	if (err < 0) {
			break;
    	}
	}while(0);

	if (err < 0)
	{
		ALOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	else
	{
	    RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &response, sizeof(int));
	}
	at_response_free(p_response);

	return;
}

static void requestSignalStrength(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
    ATResponse *p_response = NULL;
    int err;
    int response[2];
    char *line;

	do
	{
    	err = ril_send_command_singleline(thiz, "AT+CSQ", "+CSQ:", &p_response);
    	if (err < 0 || p_response->success == 0) {
    	    break;
    	}

    	line = p_response->p_intermediates->line;

    	err = at_tok_start(&line);
    	if (err < 0) break;

    	err = at_tok_nextint(&line, &(response[0]));
    	if (err < 0) break;
		response[0] = calibrateSignalStrength(response[0]);

    	err = at_tok_nextint(&line, &(response[1]));
    	if (err < 0) break;
	}while(0);

	if (err < 0)
	{
		ALOGE("requestSignalStrength must never return an error when radio is on");
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	else
	{
    	RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, response, sizeof(response));
	}
    at_response_free(p_response);
    return;
}

static void requestRegistrationState(RIL* thiz, int request, void *data,
                                        size_t datalen, RIL_Token t)
{
    int err;
    int response[4] = {0};
    char * responseStr[4];
    ATResponse *p_response = NULL;
    char *line, *p;
    int commas;
    int skip;
    int count = 3;
	int i = 0;

    err = ril_send_command_singleline(thiz, "AT+CREG?", "+CREG:", &p_response);
	/*
    if(RIL_GetNetType(thiz) > 3)
    {
        err = ril_send_command_singleline(thiz, "AT+CREG?", "+CREG:", &p_response);
    }
    else
    {
        err = ril_send_command_singleline(thiz, "AT+CGREG?", "+CGREG:", &p_response);
    }
    */
    if (err != 0 || p_response == NULL || p_response->p_intermediates == NULL || p_response->p_intermediates->line == NULL) goto error;

	ALOGD("########################: err=%d", err);

    line = p_response->p_intermediates->line;

    err = at_tok_start(&line);
    if (err < 0) goto error;

    /* Ok you have to be careful here
     * The solicited version of the CREG response is
     * +CREG: n, stat, [lac, cid]
     * and the unsolicited version is
     * +CREG: stat, [lac, cid]
     * The <n> parameter is basically "is unsolicited creg on?"
     * which it should always be
     *
     * Now we should normally get the solicited version here,
     * but the unsolicited version could have snuck in
     * so we have to handle both
     *
     * Also since the LAC and CID are only reported when registered,
     * we can have 1, 2, 3, or 4 arguments here
     *
     * finally, a +CGREG: answer may have a fifth value that corresponds
     * to the network type, as in;
     *
     *   +CGREG: n, stat [,lac, cid [,networkType]]
     */

    /* count number of commas */
    commas = 0;
    for (p = line ; *p != '\0' ;p++) {
        if (*p == ',') commas++;
    }

    switch (commas) {
        case 0: /* +CREG: <stat> */
            err = at_tok_nextint(&line, &response[0]);
            if (err < 0) goto error;
            /*broncho wupeng add begin, ignore roaming.*/
            if(response[0] == 5) response[0] = 1; // change to register home network. 
            /*broncho wupeng add end.*/
            response[1] = -1;
            response[2] = -1;
        break;

        case 1: /* +CREG: <n>, <stat> */
            err = at_tok_nextint(&line, &skip);
            if (err < 0) goto error;
            err = at_tok_nextint(&line, &response[0]);
            if (err < 0) goto error;
			/*broncho wupeng add begin, ignore roaming.*/
            if(response[0] == 5) response[0] = 1; // change to register home network. 
            /*broncho wupeng add end.*/
            response[1] = -1;
            response[2] = -1;
            if (err < 0) goto error;
        break;

        case 2: /* +CREG: <stat>, <lac>, <cid> */
            err = at_tok_nextint(&line, &response[0]);
            if (err < 0) goto error;
            err = at_tok_nexthexint(&line, &response[1]);
            if (err < 0) goto error;
            err = at_tok_nexthexint(&line, &response[2]);
            if (err < 0) goto error;
			/*broncho wupeng add begin, ignore roaming.*/
            if(response[0] == 5) response[0] = 1; // change to register home network. 
            /*broncho wupeng add end.*/

        break;

        case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
            err = at_tok_nextint(&line, &skip);
            if (err < 0) goto error;
            err = at_tok_nextint(&line, &response[0]);
            if (err < 0) goto error;
            err = at_tok_nexthexint(&line, &response[1]);
            if (err < 0) goto error;
            err = at_tok_nexthexint(&line, &response[2]);
            if (err < 0) goto error;
			/*broncho wupeng add begin, ignore roaming.*/
            if(response[0] == 5) response[0] = 1; // change to register home network. 
            /*broncho wupeng add end.*/

        break;
        default:
            goto error;
    }
	
	mmSetRegSuccess(thiz, response[0] == 5 || response[0] == 1);	
	if(response[0] == 5 || response[0] == 1) {
		//initSyscfg(thiz);
	}

    asprintf(&responseStr[0], "%d", response[0]);
    asprintf(&responseStr[1], "%x", response[1]);
    asprintf(&responseStr[2], "%x", response[2]);

    if (count > 3)
        asprintf(&responseStr[3], "%d", response[3]);

    RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
    at_response_free(p_response);

	for(i = 0; i < 3; i++)
	{
		free(responseStr[i]);
		responseStr[i] = NULL;
	}

    return;
error:
    ALOGE("requestRegistrationState must never return an error when radio is on");
    RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
    at_response_free(p_response);
}

static void requestOperator(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
    int i = 0;
    char *response[3] = {0};
	char cmd[32] = {0};
	int success = 1;
	ATResponse* p_resp = NULL;
	int mode = 0;
	int format = 0;
	
	if(ril_command_exec_for_result(thiz, "AT+COPS=3,0"))
	{
		usleep(100 * 1000);
	}

	for (i = 0; i < PLMN_NAME_FORMAT_NR; i++)
	{
		snprintf (cmd, 32, "AT+COPS=3,%d", i);
		if (!ril_command_exec_for_result(thiz, cmd))
		{
			success = 0;
			break;
		}
		
		if (!ril_command_exec_singleline_full_for_result(thiz, "AT+COPS?", 60000, "+COPS:", &p_resp))
		{
			success = 0;
			break;
		}
		if (!at_line_scanf_int_int_string (p_resp->p_intermediates->line, 
				&mode, &format, &response[i]))
		{
			success = 0;
			at_response_free(p_resp);
			break;
		}
		response[i] = strdup(response[i]);
		at_response_free(p_resp);
	}

	if (success)
	{
    	RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, response, sizeof(response));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	for (i = 0; i < PLMN_NAME_FORMAT_NR; i++)
	{
		if (response[i] != NULL)
		{
			free(response[i]);
			response[i] = NULL;
		}
	}

	return;
}

int RIL_initialize_mm (RIL* thiz)
{
	ril_send_command(thiz, "AT+CREG=2", NULL);
	ril_send_command(thiz, "AT+COPS=3,2", NULL);
	ril_send_command(thiz, "AT^CURC=1", NULL);
	initSyscfg(thiz);
	return 1;
}

int gethex(const char * hexstring, int size)
{
	int re = 0;
	int tmp = 0;
	char* str = hexstring;

	while( ( NULL != *str ) && ( hexstring+size != str ) )
	{
		if ( *str >= '0' && *str <= '9' )
			tmp = *str - '0';
		else if ( *str >= 'a' && *str <= 'z' )
			tmp = *str - 'a' + 10;
		else if ( *str >= 'A' && *str <= 'Z' )
			tmp = *str - 'A' + 10;
		else
			return 0;

		re = re * 16 + tmp;
		++str;
	}
	return re;
}


static void checkRegisted(void* param)
{
	static int has_seted_3g = 0;
	RIL* thiz = (RIL*)param;
	if(RIL_GetRegistState(thiz))
	{
		int ipart1,ipart2;
		char* line = NULL;
		char * pPart3 =  NULL;
		int err = 0;
		ATResponse* p_response =  NULL;

		ALOGD(" detect whether 2g or 3g");
		err = ril_send_command_singleline(thiz, "AT+CRSM=192,28474,0,0,15", "+CRSM:", &p_response);
		if(err != 0 || p_response->success == 0)
		{
			RIL_requestTimedCallback(thiz, checkRegisted, thiz, &TIMEVAL_REGPOLL);	
			at_response_free(p_response);
			return;
		}
		line = p_response->p_intermediates->line;

		err = at_tok_start(&line);
		err = at_tok_nextint(&line, &(ipart1));
		err = at_tok_nextint(&line, &(ipart2));

		if (at_tok_hasmore(&line))
		{
			err = at_tok_nextstr(&line, &(pPart3));
		}

		if (gethex(pPart3, 2) == 0x62 && !has_seted_3g)  //3//3g
		{
			has_seted_3g = 1;
			ril_send_command(thiz, "AT^SYSCFG=14,0,40000000,2,2", NULL); //WCDMA ONLY
			RIL_requestTimedCallback (thiz, checkRegisted, thiz, &TIMEVAL_REGPOLL);
		}
		at_response_free(p_response);
	} else if (has_seted_3g) {
		ril_send_command(thiz, "AT^SYSCFG=2,0,40000000,2,2", NULL);
	}
}

static void initSyscfg(RIL* thiz)
{
	ril_send_command(thiz, "AT^SYSCFG=2,0,40000000,2,2", NULL);
   	RIL_requestTimedCallback (thiz, checkRegisted, thiz, &TIMEVAL_SYSCFGPATCH);
	sleep(10);

	return;
}


static void onUnsolicited_Csq(RIL* thiz, const char* s)
{
	char* line = NULL;
	char* dump_str = NULL;
	static int sCSQ[2] = {99, 99};
	int err = 0;

	dump_str = strdup(s);
	line = dump_str;
	do
	{
		err = at_tok_start(&line);
		if (err < 0) break;

		err = at_tok_nextint(&line, &sCSQ[0]);
		if (err < 0) break;

		err = at_tok_nextint(&line, &sCSQ[1]);
		if (err < 0) break;

		if (sCSQ[0] != 99)
		{
			RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SIGNAL_STRENGTH, sCSQ, sizeof(sCSQ));
		}
	}while (0);
	free(dump_str);

	return;
}

static void onUnsolicited_Nitz(RIL* thiz, const char* s)
{
	char* response = NULL;
	char* line = NULL;
	char* dump_s = NULL;
	int err = 0;

	dump_s = strdup(s);
	line = dump_s;
	at_tok_start(&line);
	err = at_tok_nextstr(&line, &response);
	if (err == 0) 
	{
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_NITZ_TIME_RECEIVED, response, strlen(response));
	}
	free (dump_s);

	return;
}

static void onUnsolicited_CSQLVL(RIL* thiz, const char* s)
{
	char* line = NULL;
	char* dump_str = NULL;
	static int sCSQ[2] = {99, 99};
	int err = 0;
	int csq_level = 0;

	dump_str = strdup(s);
	line = dump_str;
	do
	{
		err = at_tok_start(&line);
		if (err < 0) break;

		err = at_tok_nextint(&line, &csq_level);
		if (err < 0) break;

		if(csq_level == 0)sCSQ[0] = 99;
		else if(csq_level == 1)sCSQ[0] = 4;
		else if(csq_level == 2)sCSQ[0] = 7;
		else if(csq_level == 3)sCSQ[0] = 11;
		else if(csq_level == 4)sCSQ[0] = 12;

		if (sCSQ[0] != 99)
		{
			RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SIGNAL_STRENGTH, sCSQ, sizeof(sCSQ));
		}
	}while (0);
	free(dump_str);

	return;

}

static void onUnsolicited_RSSI(RIL* thiz, const char* s)
{
	/*
	 * explain: usually the RIL_UNSOL_SIGNAL_STRENGTH msg gets from "+CSQ: xx,xx"
	 * but as this modem has no such specified urc, we use "+RSSI: xx" instead, which the <ber> field is always
	 * filled with 99.
	 * */
	char* line = NULL;
	char* dump_str = NULL;
	static int sCSQ[2] = {99, 99};
	int err = 0;

	dump_str = strdup(s);
	line = dump_str;
	do
	{
		err = at_tok_start(&line);
		if (err < 0) break;

		err = at_tok_nextint(&line, &sCSQ[0]);
		if (err < 0) break;

		if (sCSQ[0] != 99)
		{
			RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SIGNAL_STRENGTH, sCSQ, sizeof(sCSQ));
		}
	}while (0);
	free(dump_str);

	return;
}


int RIL_onUnsolicited_mm (RIL* thiz, const char* s)
{
	int ret = 1;
	int sCSQ[2] = {15, 99};
	int state = 0;
	static int first = 1;

	if (strStartsWith (s, "+CREG:") || strStartsWith(s, "^MODE:") || strStartsWith(s, "^SRVST"))
	{
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);
		/* broncho yinlijun add begin */
		//模块不会主动上报，所以，在第一次注册成功后，上报一个假的信号。
		sscanf(s, "+CREG: %d", &state); 
		ALOGD("========>%d %d", first, state);
		if (first && (state == 1 || state == 5))
		{
			RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SIGNAL_STRENGTH, sCSQ, sizeof(sCSQ));
			first = 0;
		}
		/* broncho yinlijun add end */
	}
	else if(strStartsWith(s, "^RSSI:"))
	{
		onUnsolicited_RSSI(thiz, s);
	}
	else if(strStartsWith(s, "^CSQLVL:"))
	{
		// broncho yinlijun delete, ignore CSQLVL
		//onUnsolicited_CSQLVL(thiz, s);
	}
	else
	{
		ret = 0;
	}

	return ret;
}

int RIL_onRequest_mm (RIL* thiz, int request, void *data, size_t datalen, RIL_Token t)
{
	switch (request)
	{
	case RIL_REQUEST_SIGNAL_STRENGTH:
		requestSignalStrength(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_REGISTRATION_STATE:
		requestRegistrationState(thiz, request, data, datalen, t);
		break;

	case RIL_REQUEST_OPERATOR:
		requestOperator(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
		requestQueryNetworkSelectionMode(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
		requestSetNetworkSelectionAutomatic(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
		requestSetNetworkSelectionManual(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
		requestQueryAvailableNetworks(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SCREEN_STATE:
		requestQueryScreenState(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_LOCATION_UPDATES:
		requestSetLocationUpdates(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
		requestSetPreferredNetworkType(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
		requestGetPreferredNetworkType(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;
	/*broncho wupeng add begin.*/
	case RIL_REQUEST_CALL_GPSONE:
		requestCallGpsone(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_GPS:
		requestSetGps(thiz, data, datalen, t);
		break;

	/*broncho wupeng add end.*/
	default:
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;
	}

	return 1;
}


